import add from './add'
import remove from './remove'
import alert from './alert'
import get from './get'
import {handleWhere} from '../../sync/'

/**
 * 可以不要这部分，因为非刻意设置，不会本地请求！
 * 在小程序端可以考虑优化掉
 */

module.exports = {
	add, remove, alert, get,
	/**
	 * 查询子级数据
	 */
	getTreeChild(cloudObj, params, config = {}, isApp = true) {
		return get(cloudObj, params, config, isApp)
	},
	/**
	 * 查询父级数据
	 * 可以查询所有，设置getTreePath.limitLevel = 'all'，需指定parentKey！
	 * getTreePath.isNew的特点是：查到之后，返回一个一维数组；反之维持原来的多维数组的形式
	 */
	getTreeParent(cloudObj, params, config = {}, isApp = false) {
		return new Promise((resolve, reject) => {
			var valueKey, symbol, // 要查询全部数据的一些基础值
				isNew, // 是否采用新的数据格式
				dataList = [] // 最终的数据
			const {parentKey, getTreePath} = params.where
			if (getTreePath) {
				if (getTreePath.limitLevel === 'all') { // 有可能需要循环查询
					getTreePath.limitLevel = 10
					const {startWidth} = getTreePath
					if (startWidth.indexOf('===') > -1) {
						symbol = '==='
					} else {
						symbol = '=='
					}
					valueKey = startWidth.split(symbol)[0]
				}
				isNew = !!getTreePath.isNew
				delete getTreePath.isNew
			}
			const cycle = (parentValue) => {
				if (parentValue) {
					getTreePath.startWidth = `${valueKey}${symbol}'${parentValue}'`
				}
				get(cloudObj, params, config, isApp).then(res => {
					if (isNew) {
						const tempArr = [] // 必须被dataList逐个插入到最前面
						const handleArray = (array) => {
							if (array && array.length > 0) {
								const item = array[0]
								const {children} = item
								delete item.children
								tempArr.unshift(item)
								handleArray(children)
							}
						}
						handleArray(res.data)
						tempArr.forEach(item => { // 必须要往前插入
							dataList.unshift(item)
						})
					} else {
						if (dataList.length > 0) {
							if (res.data.length > 0) {
								res.data[res.data.length - 1].children = dataList
							}
						}
						dataList = res.data
					}
					if (parentKey && valueKey && res.data[0][parentKey]) {
						cycle(res.data[0][parentKey])
					} else {
						resolve(request.getResult({data: dataList, message: '父级数据获取完成'}))
					}
				}).catch(reject)
			}
			cycle()
		})
	},
	/**
	 * 查询到数据后完全清除再直接新增
	 * params：所有查询条件。如果params.where是对象并且value值非对象，则自动转为新增的条件
	 * 	data：要新增的数据
	 * 	isDelete：是否真的删除
	 * 	isReturn：是否返回新增后的数据
	 * 	MainKey：假删除时新增的关键数据。将根据这个字段值来判断是否恢复假删除的状态改为修改。要求MainKey值唯一
	 */
	removeAdd(cloudObj, params, config = {}, isApp = true) {
		return new Promise((resolve, reject) => {
			var {data, MainKey, where} = params
			remove(cloudObj, params, config, isApp).then(res => {
				const {isReturn, isDelete} = params
				// 最终新增的动作
				const addAction = (addData = data) => {
					add(cloudObj, {isReturn, data: addData, addType: {requiredType: 0,  onlyType: -1}}, config, isApp).then(resolve).catch(reject)
				}
				/**
				 * 直接新增。只做必要性判断，忽略唯一性判断
				 * 如果不是真的删除，新增的时候必须清理掉_id
				 */
				if (isDelete) {
					// 真删除。直接新增
					addAction(data)
				} else {
					/**
					 * 假删除。以规格设置为例。规格信息中设定MainKey为code
					 * 1，没有判断的字段MainKey，新增的时候必须清理掉_id
					 * 2，有MainKey的情况：
					 * 		0，原来的所有数据都假删除状态，remove为true。已经完成
					 * 		1，查询原来的所有数据中的MainKey是否存在
					 * 		2，存在的直接修改，remove要改为false。由于修改只能单个进行，所以实际操作是保留_id、HISTORY等基础信息，先真的删除后新增
					 * 		3，不存在的直接新增
					 */
					if (!Array.isArray(data)) {
						data = [data]
					}
					const filter = []
					data.forEach(item => {
						delete item._id
						filter.push(item[MainKey])
						if (where) { // 将要添加的信息加入删除的条件，以保证数据一致性
							Object.keys(where).forEach(key => {
								if (typeof(where[key]) !== 'object') {
									item[key] = where[key]
								}
							})
						}
					})
					if (MainKey) {
						// 查询的数组；要新增的内容；要真的删除的内容
						const addArr = [], removeAdd = []
						// 1，查询原来的所有数据中的MainKey是否存在。要求MainKey对应的值唯一
						var fetchPatams = {remove: 2}
						fetchPatams[MainKey] = {filterType: 'select', filter}
						// 需要查询历史信息
						get(cloudObj, fetchPatams, {...config, defuseKeys: []}, isApp).then(res => {
							data.forEach(item => {
								var index = -1
								for (let i = 0; i < res.data.length; i++) {
									if (res.data[i][MainKey] === item[MainKey]) {
										index = i
										break
									}
								}
								if (index === -1) {
									// 3，不存在的直接新增
									addArr.push(item)
								} else {
									/**
									 * 2，存在的直接修改，remove要改为false
									 * 由于修改只能单个进行，所以实际操作是保留_id、HISTORY等基础信息，先真的删除后新增
									 */
									// 需要删除的id
									removeAdd.push(res.data[index]._id)
									// 需要保留的信息
									const history = JSON.parse(JSON.stringify(item))
									const retain = ["_id", "remark", "creat_type", "creator", "timestamp", "alert_user", "alert_time", "HISTORY"]
									retain.forEach(key => {
										item[key] = res.data[index][key]
									})
									item.remove = false
									if (item.HISTORY) {
										item.HISTORY.unshift(history)
									} else {
										item.HISTORY = [history]
									}
									addArr.push(item)
								}
							})
							if (removeAdd.length > 0) {
								remove(cloudObj, {isDelete: true, doc: removeAdd}, config, isApp).then(res => {
									addAction(addArr)
								}).catch(reject)
							} else {
								addAction(addArr)
							}
						})
					} else {
						addAction(data)
					}
				}
			}).catch(reject)
		})
	},
	
	/**
	 * 查询到就修改，查不到就新增
	 * params：所有查询条件
	 * data：要修改或新增的数据
	 * isReturn：是否返回新增或修改后的数据。默认新增时返回，修改时不返回
	 */
	addAlert(cloudObj, params, config = {}, isApp = true) {
		return new Promise((resolve, reject) => {
			const handleAdd = () => {
				// 新增时默认返回信息
				const {isReturn = true, data} = params
				add(cloudObj, {isReturn, data}, config, isApp).then(resolve).catch(reject)
			}
			const handleAlert = (doc) => {
				// 修改时默认不返回信息
				const {isReturn, data} = params
				alert(cloudObj, {where: {doc}, isReturn, data}, config, isApp).then(resolve).catch(reject)
			}
			const db = handleWhere(cloudObj, params, config, isApp)
			if (db) {
				// 要能够查到才修改
				db.get().then(res => {
					if (res.result) {
						res = res.result
					}
					if (res.data.length > 0) {
						const ids = []
						res.data.map(item => {
							ids.push(item._id)
						})
						handleAlert(ids)
					} else {
						// 再新增
						handleAdd()
					}
				}).catch(reject)
			} else {
				// 直接新增
				handleAdd()
			}
		})
	},
	
	/**
	 * 批量修改
	 * 数据库的逻辑是只能修改单个。批量修改的逻辑是，先查询再删除后新增。
	 * 查询到数据后，写入HISTORY数据，再根据_id全部真的删除，然后全部新增
	 * data：对象。key为_id，value为要修改的内容
	 */
	batchAlert(cloudObj, params, config = {}, isApp = true) {
		return new Promise((resolve, reject) => {
			const {data, isReturn} = params
			const doc = []
			Object.keys(data).forEach(key => {
				doc.push(key)
			})
			// 1，查询数据，包含假删除的，包含历史信息
			get(cloudObj, {remove: 1, doc}, {...config, defuseKeys: []}, isApp).then(res => {
				const addData = [], sourceData = JSON.parse(JSON.stringify(res.data))
				res.data.map(item => {
					var obj = data[item._id]
					if (!item.HISTORY) {
						item.HISTORY = []
					}
					// 记录修改信息。前端不支持复杂修改
					if (isApp) {
						item.HISTORY = [JSON.parse(JSON.stringify(obj))]
						item.HISTORY[0].isApp = true
					} else {
						item.HISTORY.unshift(JSON.parse(JSON.stringify(obj)))
					}
					addData.push({
						...item,
						...obj
					})
				})
				// 2，全部删除
				remove(cloudObj, {doc, isDelete: true}, config, isApp).then(res => {
					// 全部新增
					add(cloudObj, {data: addData, isReturn, addType: {force: true, requiredType: -1, onlyType: -1}}, config, isApp).then(res => {
						addData.map(item => {
							delete item.HISTORY
						})
						resolve(getResult({data: addData, message: '批量修改成功'}))
					}).catch(error => {
						// 可能的原因是数据格式不正确，无法新增通过。所以必须将删除的数据再原样新增回去
						add(cloudObj, {data: sourceData, addType: {force: true, requiredType: -1, onlyType: -1}}, config, isApp).then(res => {
							reject(getError('数据格式有误，批量修改出错'))
						}).catch(err => {
							/**
							 * 这一步如果新增出错，就要记录了
							 */
							const {space, name} = cloudObj
							reject(getError('数据已丢失，请联系管理员', 999, {
								error, table: name,
								function: 'batchAlert', 
								keyData: sourceData,
								description: '批量修改，删除数据后新增新数据失败，新增原数据也失败'
							}))
						})
					})
				}).catch(reject)
			}).catch(reject)
		})
	},
}